
/****************************************************************************/
/*Copyright (c) 2011, Florent DEVILLE.                                      */
/*All rights reserved.                                                      */
/*                                                                          */
/*Redistribution and use in source and binary forms, with or without        */
/*modification, are permitted provided that the following conditions        */
/*are met:                                                                  */
/*                                                                          */
/* - Redistributions of source code must retain the above copyright         */
/*notice, this list of conditions and the following disclaimer.             */
/* - Redistributions in binary form must reproduce the above                */
/*copyright notice, this list of conditions and the following               */
/*disclaimer in the documentation and/or other materials provided           */
/*with the distribution.                                                    */
/* - The names of its contributors cannot be used to endorse or promote     */
/*products derived from this software without specific prior written        */
/*permission.                                                               */
/* - The source code cannot be used for commercial purposes without         */ 
/*its contributors' permission.                                             */
/*                                                                          */
/*THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS       */
/*"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT         */
/*LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS         */
/*FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE            */
/*COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,       */
/*INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,      */
/*BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;          */
/*LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER          */
/*CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT        */
/*LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN         */
/*ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE           */
/*POSSIBILITY OF SUCH DAMAGE.                                               */
/****************************************************************************/


#include "Visualisation.h"

//include for zeromemory function
#define VC_EXTRALEAN
#define WIN32_LEAN_AND_MEAN 
#include <windows.h>

//initialise the instance object to 0
CVisualisation* CVisualisation::m_instance = 0;

//Constructor
CVisualisation::CVisualisation(void)
	:m_screenBuffer(0), m_surfaceScreenBuffer(0), m_window(0), m_reverseScreenBuffer(0), 
	m_surfaceReversedScreenBuffer(0)
{
}

//Destructor
CVisualisation::~CVisualisation(void)
{
	//delete the screen buffers
	if (m_screenBuffer != 0)
	{
		delete[] m_screenBuffer;
		m_screenBuffer = 0;
	}
	if (m_reverseScreenBuffer != 0)
	{
		delete[] m_reverseScreenBuffer;
		m_reverseScreenBuffer = 0;
	}

	//delete the sdl surface
	if (m_surfaceScreenBuffer != 0)
	{
		SDL_FreeSurface(m_surfaceScreenBuffer);
		m_surfaceScreenBuffer = 0;
	}
	if (m_surfaceReversedScreenBuffer != 0)
	{
		SDL_FreeSurface(m_surfaceReversedScreenBuffer);
		m_surfaceReversedScreenBuffer = 0;
	}
	if(m_window != 0)
	{
		SDL_FreeSurface(m_window);
		m_window = 0;
	}

	//close sdl
	SDL_Quit();
}

//return the unique instance of the CVisualisation class
CVisualisation& CVisualisation::getInstance()
{
	if (m_instance == 0)
		m_instance = new CVisualisation();

	return *m_instance;
}

//delete the singleton
void CVisualisation::close()
{
	if(m_instance != 0)
	{
		delete m_instance;
		m_instance = 0;
	}
}


//initialise the window
bool CVisualisation::init(unsigned int width, unsigned int height, unsigned int bpp)
{
	//set the variables
	m_width = width;
	m_height = height;
	m_bpp = bpp;

	//calculate the byte per pixel
	unsigned int bytesPerPixel = m_bpp / 8;

	//calculate the size of the buffers
	int sizeOfScreenInBytes = m_width * m_height * bytesPerPixel;
	
	//create the screen buffer
	m_screenBuffer = new char[sizeOfScreenInBytes];
	ZeroMemory(m_screenBuffer, sizeof(char)*sizeOfScreenInBytes); 

	//create the reverse screen buffer
	m_reverseScreenBuffer = new char[sizeOfScreenInBytes];

	//create the surface for the rendered picture
	m_surfaceScreenBuffer = SDL_CreateRGBSurfaceFrom(m_screenBuffer, m_width, m_height, m_bpp, m_width*bytesPerPixel, 0, 0, 0, 0);

	//create the surface for the reversed rendered picture
	m_surfaceReversedScreenBuffer = SDL_CreateRGBSurfaceFrom(m_reverseScreenBuffer, m_width, m_height, m_bpp, m_width*bytesPerPixel, 0, 0, 0, 0);

	//initialise the SDL
	if(SDL_Init(SDL_INIT_VIDEO) == -1)
		return false;

	//initialise the SDL video mode
	m_window = SDL_SetVideoMode(m_width, m_height, m_bpp, SDL_HWSURFACE);
	SDL_WM_SetCaption(" MaLoRT : The Mac Lovin' Ray Tracer | Florent DEVILLECHABROL", 0);

	return true;
}

//calculate the reverse screen buffer (every line inversed) from the current screen buffer
bool CVisualisation::createReverseScreenBuffer()
{
	//calculate the length of a line in bytes
	unsigned int widthInBytes = m_width * 3;

	//reverse the buffer into
	for(unsigned int i = 0; i<m_height; i++) //for every line
	{
		int offsetDest = i * widthInBytes;
		int offsetSrc = (m_height - i - 1) * widthInBytes;
		memcpy(m_reverseScreenBuffer + offsetDest, m_screenBuffer + offsetSrc, widthInBytes);
	}

	return true;
}

//prepare sdl to render
void CVisualisation::preRender()
{
}

//render on the screen
void CVisualisation::doRender()
{
	//position of the texture in the screen
	SDL_Rect position;
    position.x = 0;
    position.y = 0;

	//blit the rendered picture onto the screen
	SDL_BlitSurface(m_surfaceScreenBuffer, NULL, m_window, &position );
}

//refresh window
void CVisualisation::postRender()
{
	SDL_Flip(m_window);
}

//get a pointer to the screen buffer
char* CVisualisation::getScreenBuffer() const
{
	return m_screenBuffer;
}

//get a pointer to the reverse screen buffer
char* CVisualisation::getReverseScreenBuffer() const
{
	return m_reverseScreenBuffer;
}

//save the current screen buffer into a bmp file
bool CVisualisation::saveScreenBufferToBMP(const char* filename)const
{
	SDL_SaveBMP(m_window, filename);
	return true;
}

bool CVisualisation::saveReversedScreenBufferToBMP(const char* filename)const
{
	SDL_SaveBMP(m_surfaceReversedScreenBuffer, filename);
	return true;
}